// Copyright 2006 Team AWESOME. All Rights Reserved.

public class Hasher {

  private static final int[] SEED = new int[] {
      2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
      71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
      151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
      229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307,
      311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389,
      397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467,
      479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571,
      577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653,
      659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751,
      757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853,
      857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
      953, 967, 971, 977, 983, 991, 997, 1009, 1013};

  public static int[] computeHashes(String str, int count) {
    long[] result = new long[count];
    // for (int j = 0; j < count; ++j) {
    // int h = SEED[j + 20];
    // for (int i = 0, c = bytes.length; i < c; ++i) {
    // h = 31 * h + bytes[i];
    // }
    // h += ~(h << 9);
    // h ^= (h >>> 14);
    // h += (h << 4);
    // h ^= (h >>> 10);
    // result[j] = h;
    // }

    for (int i = 0; i < count; ++i) {
      switch (i) {
        case 0:
          result[i] = APHash(str);
          break;
        case 1:
          result[i] = BKDRHash(str);
          break;
        case 2:
          result[i] = BPHash(str);
          break;
        case 3:
          result[i] = DEKHash(str);
          break;
        case 4:
          result[i] = DJBHash(str);
          break;
        case 5:
          result[i] = ELFHash(str);
          break;
        case 6:
          result[i] = FNVHash(str);
          break;
        case 7:
          result[i] = JSHash(str);
          break;
        case 8:
          result[i] = PJWHash(str);
          break;
        case 9:
          result[i] = RSHash(str);
          break;
        case 10:
          result[i] = SDBMHash(str);
          break;
      }
    }

    int[] intres = new int[count];
    for (int i = 0; i < count; ++i) {
      int h = (int) result[i];
       h += ~(h << 9);
       h ^= (h >>> 14);
       h += (h << 4);
       h ^= (h >>> 10);
      intres[i] = h;

    }
    return intres;
  }

  static long RSHash(String str) {
    int b = 378551;
    int a = 63689;
    long hash = 0;

    for (int i = 0; i < str.length(); i++) {
      hash = hash * a + str.charAt(i);
      a = a * b;
    }

    return (hash & 0x7FFFFFFF);
  }

  /* End Of RS Hash Function */

  static long JSHash(String str) {
    long hash = 1315423911;

    for (int i = 0; i < str.length(); i++) {
      hash ^= ((hash << 5) + str.charAt(i) + (hash >> 2));
    }

    return (hash & 0x7FFFFFFF);
  }

  /* End Of JS Hash Function */

  static long PJWHash(String str) {
    long BitsInUnsignedInt = (long) (4 * 8);
    long ThreeQuarters = (long) ((BitsInUnsignedInt * 3) / 4);
    long OneEighth = (long) (BitsInUnsignedInt / 8);
    long HighBits = (long) (0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth);
    long hash = 0;
    long test = 0;

    for (int i = 0; i < str.length(); i++) {
      hash = (hash << OneEighth) + str.charAt(i);

      if ((test = hash & HighBits) != 0) {
        hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
      }
    }

    return (hash & 0x7FFFFFFF);
  }

  /* End Of P. J. Weinberger Hash Function */

  static long ELFHash(String str) {
    long hash = 0;
    long x = 0;

    for (int i = 0; i < str.length(); i++) {
      hash = (hash << 4) + str.charAt(i);

      if ((x = hash & 0xF0000000L) != 0) {
        hash ^= (x >> 24);
        hash &= ~x;
      }
    }

    return (hash & 0x7FFFFFFF);
  }

  /* End Of ELF Hash Function */

  static long BKDRHash(String str) {
    long seed = 131; // 31 131 1313 13131 131313 etc..
    long hash = 0;

    for (int i = 0; i < str.length(); i++) {
      hash = (hash * seed) + str.charAt(i);
    }

    return (hash & 0x7FFFFFFF);
  }

  /* End Of BKDR Hash Function */

  static long SDBMHash(String str) {
    long hash = 0;

    for (int i = 0; i < str.length(); i++) {
      hash = str.charAt(i) + (hash << 6) + (hash << 16) - hash;
    }

    return (hash & 0x7FFFFFFF);
  }

  /* End Of SDBM Hash Function */

  static long DJBHash(String str) {
    long hash = 5381;

    for (int i = 0; i < str.length(); i++) {
      hash = ((hash << 5) + hash) + str.charAt(i);
    }

    return (hash & 0x7FFFFFFF);
  }

  /* End Of DJB Hash Function */

  static long DEKHash(String str) {
    long hash = str.length();

    for (int i = 0; i < str.length(); i++) {
      hash = ((hash << 5) ^ (hash >> 27)) ^ str.charAt(i);
    }

    return (hash & 0x7FFFFFFF);
  }

  /* End Of DEK Hash Function */

  static long BPHash(String str) {
    long hash = 0;

    for (int i = 0; i < str.length(); i++) {
      hash = hash << 7 ^ str.charAt(i);
    }

    return (hash & 0x7FFFFFFF);
  }

  /* End Of BP Hash Function */

  static long FNVHash(String str) {
    long fnv_prime = 0x811C9DC5;
    long hash = 0;

    for (int i = 0; i < str.length(); i++) {
      hash *= fnv_prime;
      hash ^= str.charAt(i);
    }

    return (hash & 0x7FFFFFFF);
  }

  /* End Of FNV Hash Function */

  static long APHash(String str) {
    long hash = 0;

    for (int i = 0; i < str.length(); i++) {
      if ((i & 1) == 0) {
        hash ^= ((hash << 7) ^ str.charAt(i) ^ (hash >> 3));
      } else {
        hash ^= (~((hash << 11) ^ str.charAt(i) ^ (hash >> 5)));
      }
    }

    return (hash & 0x7FFFFFFF);
  }
  /* End Of AP Hash Function */

}
